package com.juyu.miliao.api.controller;

import com.alibaba.fastjson.JSONObject;
import com.juyu.miliao.api.constant.PayContentType;
import com.juyu.miliao.api.service.*;
import com.juyu.miliao.common.domain.CommonHead;
import com.juyu.miliao.common.domain.Subject;
import com.juyu.miliao.common.exception.ConsumeRuntimeException;
import com.juyu.miliao.common.msg.ErrorMsg;
import com.juyu.miliao.common.util.VerifyUtil;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

@RestController
@RequestMapping()
public class AppleIapPayController {
    //购买凭证验证地址
    private static final String certificateUrl = "https://buy.itunes.apple.com/verifyReceipt";
    //测试的购买凭证验证地址
    private static final String certificateUrlTest = "https://sandbox.itunes.apple.com/verifyReceipt";
    private final Logger payNotifyLogger = LoggerFactory.getLogger("payNotify");
    @Resource
    private PayService payService;

    /**
     * 接收iOS端发过来的购买凭证-废弃 缺少校验参数transactionId
     *
     * @param receipt     请求apple校验参数
     * @param contentType 计费类型：1金币 2VIP，3：SVIP,4:铂金VIP
     * @param contentId   计费内容查询id
     * 支付校验逻辑
     * 1.校验正式环境支付地址，如校验成功则支付成功
     * 2.如果正式环境支付地址校验失败，且渠道号为 juyu_ios 则抛出异常通知前端支付失败
     * 3.如果正式环境支付地址校验失败，且渠道号不为 juyu_ios 则校验测试环境支付地址
     * 4.如果测试环境支付地址校验成功，则支付成功，否则支付失败
     */
    @PostMapping("/IapPayCertificate")
    public void setIapCertificate(HttpServletRequest request, Authentication token,
                                  @RequestParam("receipt") String receipt,
                                  @RequestParam("contentType") int contentType,
                                  @RequestParam("contentId") int contentId,
                                  @RequestParam(value = "robotOrderType",required = false) Integer robotOrderType,
                                  @RequestParam(value = "h5OrderType",required = false) Integer h5OrderType,
                                  @RequestParam(value = "payNum",required = false) Integer payNum) throws IOException {
        if (StringUtils.isEmpty(receipt) && !StringUtils.isNotEmpty(receipt)) {
            throw new ConsumeRuntimeException("参数错误,receipt不能为null");
        }
        if (contentType != PayContentType.PAY_CONTENT_TYPE_GOLD.getCode()
                && contentType != PayContentType.PAY_CONTENT_TYPE_VIP.getCode()
                && contentType != PayContentType.PAY_SVIP_TYPE_VIP.getCode())
            throw new ConsumeRuntimeException("参数错误,contentType错误");
        if(robotOrderType == null){
            robotOrderType = 0;
        }
        if(h5OrderType == null){
            h5OrderType = 1;
        }
        if(payNum == null){
            payNum = 1;
        }
        //验证请求头 兼容老版本
        CommonHead com = VerifyUtil.verifyCommonHead(request);
        Subject subject = (Subject) token.getPrincipal();
        payNotifyLogger.info(com.toString());
        payNotifyLogger.info("参数打印:userId---{}", subject.getId());
        //验证正式环境
        String returnStr = sendHttpsCoon(certificateUrl, receipt);
        JSONObject jsStr = JSONObject.parseObject(returnStr);
        String status = jsStr.get("status").toString();
        if (!status.equals("0")){
            if (com.getChannel().equals("juyu_ios")) {
                throw new ConsumeRuntimeException(new ErrorMsg(HttpStatus.BAD_REQUEST, "30001",
                        "发送请求返回结果错误错误exception:" + jsStr.get("status").toString()));
            }
            //正式环境验证失败，验证测试环境
            returnStr = sendHttpsCoon(certificateUrlTest, receipt);
            jsStr = JSONObject.parseObject(returnStr);
            status = jsStr.get("status").toString();
            if (!status.equals("0")) {
                throw new ConsumeRuntimeException(new ErrorMsg(HttpStatus.BAD_REQUEST, "30001",
                        "发送请求返回结果错误错误exception:" + jsStr.get("status").toString()));
            }
        }
        payService.appleIapPay(jsStr.get("receipt").toString(), com, subject, contentType, contentId,
                                    robotOrderType,h5OrderType,payNum);
    }

    /**
     * 接收iOS端发过来的购买凭证
     *
     * @param receipt     请求apple校验参数
     * @param contentType 计费类型：1金币 2VIP，3：SVIP,4:铂金VIP
     * @param contentId   计费内容查询id
     * @param transactionId 苹果计费外部订单号
     * @param robotOrderType 是否为机器人充值 0-未知(默认)  1-登录机器人   2-注册机器人
     * @param h5OrderType 是否为h5充值 0-未知(默认)  1-原生app充值   2-h5充值
     * @param payNum 支付个数，1：默认
     * 支付校验逻辑
     * 1.校验正式环境支付地址，如校验成功则支付成功
     * 2.如果正式环境支付地址校验失败，且渠道号为 juyu_ios 则抛出异常通知前端支付失败
     * 3.如果正式环境支付地址校验失败，且渠道号不为 juyu_ios 则校验测试环境支付地址
     * 4.如果测试环境支付地址校验成功，则支付成功，否则支付失败
     */
    @PostMapping("/IapPayCertificate/notify")
    public void setIapCertificateNew(HttpServletRequest request, Authentication token,
                                     @RequestParam("receipt") String receipt,
                                     @RequestParam("contentType") int contentType,
                                     @RequestParam("contentId") int contentId,
                                     @RequestParam("transactionId") String transactionId,
                                     @RequestParam(value = "robotOrderType",required = false) Integer robotOrderType,
                                     @RequestParam(value = "h5OrderType",required = false) Integer h5OrderType,
                                     @RequestParam(value = "payNum",required = false) Integer payNum) throws IOException {
        if (StringUtils.isEmpty(receipt) && !StringUtils.isNotEmpty(receipt)) {
            throw new ConsumeRuntimeException("参数错误,receipt不能为null");
        }
        if (StringUtils.isEmpty(transactionId) && !StringUtils.isNotEmpty(transactionId)) {
            throw new ConsumeRuntimeException("参数错误,transactionId不能为null");
        }
        if (contentType != PayContentType.PAY_CONTENT_TYPE_GOLD.getCode()
                && contentType != PayContentType.PAY_CONTENT_TYPE_VIP.getCode()
                && contentType != PayContentType.PAY_SVIP_TYPE_VIP.getCode()
                && contentType != PayContentType.PAY_PLATINUM_VIP.getCode())
            throw new ConsumeRuntimeException("参数错误,contentType错误");
        if(robotOrderType == null){
            robotOrderType = 0;
        }
        if(h5OrderType == null){
            h5OrderType = 1;
        }
        if(payNum==null){
            payNum = 1;
        }
        //验证请求头 兼容老版本
        CommonHead com = VerifyUtil.verifyCommonHead(request);
        Subject subject = (Subject) token.getPrincipal();
        payNotifyLogger.info(com.toString());
        payNotifyLogger.info("参数打印:userId---{}", subject.getId());
        //验证正式环境
        String returnStr = sendHttpsCoon(certificateUrl, receipt);
        JSONObject jsStr = JSONObject.parseObject(returnStr);
        String status = jsStr.get("status").toString();
        if (!status.equals("0")){
            if (com.getChannel().equals("juyu_ios")) {
                throw new ConsumeRuntimeException(new ErrorMsg(HttpStatus.BAD_REQUEST, "30001",
                        "发送请求返回结果错误错误exception:" + jsStr.get("status").toString()));
            }
            //正式环境验证失败，验证测试环境
            returnStr = sendHttpsCoon(certificateUrlTest, receipt);
            jsStr = JSONObject.parseObject(returnStr);
            status = jsStr.get("status").toString();
            if (!status.equals("0")) {
                throw new ConsumeRuntimeException(new ErrorMsg(HttpStatus.BAD_REQUEST, "30001",
                        "发送请求返回结果错误错误exception:" + jsStr.get("status").toString()));
            }
        }
        payService.appleIapPayNew(jsStr.get("receipt").toString(), com, subject,
                contentType, contentId, transactionId , robotOrderType,h5OrderType,payNum);
    }

    /**
     * 发送请求
     *
     * @param url
     * @param code
     * @return
     */
    private String sendHttpsCoon(String url, String code) {
        if (url.isEmpty()) {
            return null;
        }
        try {
            //设置SSLContext
            SSLContext ssl = SSLContext.getInstance("SSL");
            ssl.init(null, new TrustManager[]{myX509TrustManager}, null);
            //打开连接
            HttpsURLConnection conn = (HttpsURLConnection) new URL(url).openConnection();
            //设置套接工厂
            conn.setSSLSocketFactory(ssl.getSocketFactory());
            //加入数据
            conn.setRequestMethod("POST");
            conn.setDoOutput(true);
            conn.setRequestProperty("Content-type", "application/json");
            BufferedOutputStream buffOutStr = new BufferedOutputStream(conn.getOutputStream());
            buffOutStr.write(code.getBytes());
            buffOutStr.flush();
            buffOutStr.close();
            //获取输入流
            BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String line = null;
            StringBuffer sb = new StringBuffer();
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
            return sb.toString();
        } catch (Exception e) {
            throw new ConsumeRuntimeException(new ErrorMsg(HttpStatus.BAD_REQUEST, "30001",
                    "发送请求错误exception:" + e.getMessage()));
        }
    }

    /**
     * 重写X509TrustManager
     */
    private static TrustManager myX509TrustManager = new X509TrustManager() {
        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        }

        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        }
    };

}